import os
import sys
import importlib.util
import json
from flask import Flask, request, jsonify
from werkzeug.exceptions import HTTPException
from flask_cors import CORS

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True

# 启用CORS支持
CORS(app, resources={r"/*": {"origins": "*"}}, 
     allow_headers=['Content-Type', 'Authorization', 'X-Requested-With', 'Cache-Control', 
                   'Pragma', 'Accept', 'Accept-Encoding', 'Accept-Language', 'Connection', 
                   'Host', 'Origin', 'Referer', 'User-Agent', 'X-Forwarded-For', 'X-Real-IP'])

# 排除的文件列表
EXCLUDED_FILES = {'main', 'configuration', 'publish'}

def load_lambda_handlers():
    """扫描当前目录下的Python文件，加载lambda_handler函数"""
    handlers = {}
    current_dir = os.path.dirname(os.path.abspath(__file__))
    
    for filename in os.listdir(current_dir):
        if filename.endswith('.py') and not filename.startswith('.'):
            module_name = filename[:-3]  # 去掉.py后缀
            
            # 跳过排除的文件
            if module_name in EXCLUDED_FILES:
                continue
                
            try:
                # 动态导入模块
                spec = importlib.util.spec_from_file_location(module_name, os.path.join(current_dir, filename))
                module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(module)
                
                # 检查是否有lambda_handler函数
                if hasattr(module, 'lambda_handler'):
                    handlers[module_name] = module.lambda_handler
                    print(f"已加载Lambda处理器: {module_name}")
                    
            except Exception as e:
                print(f"加载模块 {module_name} 时出错: {e}")
                
    return handlers

# 加载所有Lambda处理器
lambda_handlers = load_lambda_handlers()

def add_cors_headers(response):
    """为响应添加CORS头"""
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, PATCH, OPTIONS'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Cache-Control, Pragma, Accept, Accept-Encoding, Accept-Language, Connection, Host, Origin, Referer, User-Agent, X-Forwarded-For, X-Real-IP'
    return response

def create_lambda_event(flask_request):
    """将Flask请求转换为Lambda事件格式（API Gateway v2）"""
    import time
    import uuid
    
    # 构建API Gateway v2格式的事件
    event = {
        "version": "2.0",
        "routeKey": f"{flask_request.method} {flask_request.path}",
        "rawPath": flask_request.path,
        "rawQueryString": flask_request.query_string.decode('utf-8') if flask_request.query_string else "",
        "headers": dict(flask_request.headers),
        "requestContext": {
            "accountId": "974303038066",
            "apiId": "hzyu2os1rd",
            "domainName": "hzyu2os1rd.execute-api.eu-north-1.amazonaws.com",
            "domainPrefix": "hzyu2os1rd",
            "http": {
                "method": flask_request.method,
                "path": flask_request.path,
                "protocol": "HTTP/1.1",
                "sourceIp": flask_request.remote_addr,
                "userAgent": flask_request.headers.get('User-Agent', '')
            },
            "requestId": str(uuid.uuid4()).replace('-', '')[:16],
            "routeKey": f"{flask_request.method} {flask_request.path}",
            "stage": "$default",
            "time": time.strftime("%d/%b/%Y:%H:%M:%S +0000", time.gmtime()),
            "timeEpoch": int(time.time() * 1000)
        },
        "isBase64Encoded": False
    }
    
    # 处理请求体
    if flask_request.method in ['POST', 'PUT', 'PATCH'] and flask_request.is_json:
        try:
            event['body'] = json.dumps(flask_request.get_json())
            event['headers']['Content-Type'] = 'application/json'
        except Exception:
            # 如果JSON解析失败，使用原始数据
            event['body'] = flask_request.data.decode('utf-8') if flask_request.data else None
    elif flask_request.data:
        event['body'] = flask_request.data.decode('utf-8')
    
    # 处理查询参数
    if flask_request.args:
        event['queryStringParameters'] = dict(flask_request.args)
    
    return event

def create_lambda_context():
    """创建Lambda上下文对象"""
    class LambdaContext:
        def __init__(self):
            self.function_name = "local_lambda"
            self.function_version = "$LATEST"
            self.invoked_function_arn = "arn:aws:lambda:local:123456789012:function:local_lambda"
            self.memory_limit_in_mb = 128
            self.remaining_time_in_millis = lambda: 30000
            self.aws_request_id = "local-request-id"
            self.log_group_name = "/aws/lambda/local_lambda"
            self.log_stream_name = "local-log-stream"
    
    return LambdaContext()

@app.route('/<function_name>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
def lambda_endpoint(function_name):
    """Lambda函数端点"""
    # 处理OPTIONS请求（预检请求）
    if request.method == 'OPTIONS':
        response = app.response_class()
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, PATCH, OPTIONS'
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Cache-Control, Pragma, Accept, Accept-Encoding, Accept-Language, Connection, Host, Origin, Referer, User-Agent, X-Forwarded-For, X-Real-IP'
        response.headers['Access-Control-Max-Age'] = '86400'
        return response, 200
    
    if function_name not in lambda_handlers:
        response = jsonify({'error': f'Lambda函数 {function_name} 未找到'})
        response.headers['Content-Type'] = 'application/json; charset=utf-8'
        response = add_cors_headers(response)
        return response, 404
    
    try:
        # 创建Lambda事件和上下文
        event = create_lambda_event(request)
        context = create_lambda_context()
        
        # 调用Lambda处理器
        result = lambda_handlers[function_name](event, context)
        
        # 处理返回结果
        if isinstance(result, dict):
            status_code = result.get('statusCode', 200)
            body = result.get('body', '')
            
            # 尝试解析body为JSON
            try:
                if isinstance(body, str):
                    body_json = json.loads(body)
                    response = jsonify(body_json)
                    response.headers['Content-Type'] = 'application/json; charset=utf-8'
                    response = add_cors_headers(response)
                    return response, status_code
                else:
                    response = jsonify(body)
                    response.headers['Content-Type'] = 'application/json; charset=utf-8'
                    response = add_cors_headers(response)
                    return response, status_code
            except (json.JSONDecodeError, TypeError):
                # 如果不是JSON，返回字符串
                response = app.response_class(
                    response=body,
                    status=status_code,
                    mimetype='text/plain; charset=utf-8'
                )
                response = add_cors_headers(response)
                return response
        else:
            # 如果不是字典，直接返回
            response = app.response_class(
                response=str(result),
                status=200,
                mimetype='text/plain; charset=utf-8'
            )
            response = add_cors_headers(response)
            return response
            
    except Exception as e:
        print(f"执行Lambda函数 {function_name} 时出错: {e}")
        response = jsonify({'error': str(e)})
        response.headers['Content-Type'] = 'application/json; charset=utf-8'
        response = add_cors_headers(response)
        return response, 500

@app.route('/', methods=['GET', 'OPTIONS'])
def index():
    """首页，显示可用的Lambda函数和交互式测试界面"""
    # 处理OPTIONS请求（预检请求）
    if request.method == 'OPTIONS':
        response = app.response_class()
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'GET, OPTIONS'
        response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With, Cache-Control, Pragma, Accept, Accept-Encoding, Accept-Language, Connection, Host, Origin, Referer, User-Agent, X-Forwarded-For, X-Real-IP'
        response.headers['Access-Control-Max-Age'] = '86400'
        return response, 200
    
    available_functions = list(lambda_handlers.keys())
    
    html = f'''
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Lambda本地测试服务器</title>
    <style>
        * {{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }}
        
        body {{
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }}
        
        .container {{
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 15px;
            box-shadow: 0 20px 40px rgba(0,0,0,0.1);
            overflow: hidden;
        }}
        
        .header {{
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }}
        
        .header h1 {{
            font-size: 2.5em;
            margin-bottom: 10px;
            font-weight: 300;
        }}
        
        .header p {{
            font-size: 1.1em;
            opacity: 0.9;
        }}
        
        .content {{
            padding: 30px;
        }}
        
        .functions-grid {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }}
        
        .function-card {{
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            border: 2px solid #e9ecef;
            transition: all 0.3s ease;
        }}
        
        .function-card:hover {{
            border-color: #4facfe;
            transform: translateY(-2px);
            box-shadow: 0 10px 20px rgba(0,0,0,0.1);
        }}
        
        .function-name {{
            font-size: 1.3em;
            font-weight: 600;
            color: #333;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid #e9ecef;
        }}
        
        .method-buttons {{
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
            margin-bottom: 15px;
        }}
        
        .method-btn {{
            padding: 8px 16px;
            border: none;
            border-radius: 6px;
            font-size: 0.9em;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s ease;
            text-decoration: none;
            display: inline-block;
        }}
        
        .method-btn.get {{ background: #28a745; color: white; }}
        .method-btn.post {{ background: #007bff; color: white; }}
        .method-btn.put {{ background: #ffc107; color: #212529; }}
        .method-btn.delete {{ background: #dc3545; color: white; }}
        
        .method-btn:hover {{
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
        }}
        
        .test-section {{
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            margin-top: 20px;
        }}
        
        .test-section h3 {{
            color: #333;
            margin-bottom: 15px;
            font-size: 1.2em;
        }}
        
        .form-group {{
            margin-bottom: 15px;
        }}
        
        .form-group label {{
            display: block;
            margin-bottom: 5px;
            font-weight: 500;
            color: #555;
        }}
        
        .form-group input, .form-group textarea, .form-group select {{
            width: 100%;
            padding: 10px;
            border: 2px solid #e9ecef;
            border-radius: 6px;
            font-size: 14px;
            transition: border-color 0.3s ease;
        }}
        
        .form-group input:focus, .form-group textarea:focus, .form-group select:focus {{
            outline: none;
            border-color: #4facfe;
        }}
        
        .form-row {{
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }}
        
        .submit-btn {{
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 6px;
            font-size: 1em;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s ease;
        }}
        
        .submit-btn:hover {{
            transform: translateY(-2px);
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
        }}
        
        .response-section {{
            margin-top: 20px;
            padding: 20px;
            background: #f8f9fa;
            border-radius: 10px;
            border-left: 4px solid #4facfe;
        }}
        
        .response-section h4 {{
            color: #333;
            margin-bottom: 10px;
        }}
        
        .response-content {{
            background: #2d3748;
            color: #e2e8f0;
            padding: 15px;
            border-radius: 6px;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            white-space: pre-wrap;
            max-height: 400px;
            overflow-y: auto;
        }}
        
        .status-success {{ color: #28a745; }}
        .status-error {{ color: #dc3545; }}
        
        .loading {{
            display: none;
            text-align: center;
            padding: 20px;
            color: #666;
        }}
        
        .spinner {{
            border: 3px solid #f3f3f3;
            border-top: 3px solid #4facfe;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 1s linear infinite;
            margin: 0 auto 10px;
        }}
        
        @keyframes spin {{
            0% {{ transform: rotate(0deg); }}
            100% {{ transform: rotate(360deg); }}
        }}
        
        .no-functions {{
            text-align: center;
            padding: 40px;
            color: #666;
            font-size: 1.1em;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 Lambda本地测试服务器</h1>
            <p>测试您的Lambda函数，支持GET、POST、PUT、DELETE操作</p>
        </div>
        
        <div class="content">
            <h2 style="margin-bottom: 20px; color: #333;">可用的Lambda函数</h2>
            
            <div class="functions-grid">
    '''
    
    if available_functions:
        for func_name in available_functions:
            html += f'''
                <div class="function-card">
                    <div class="function-name">📁 {func_name}</div>
                    <div class="method-buttons">
                        <a href="/{func_name}" class="method-btn get" target="_blank">GET</a>
                        <button class="method-btn post" onclick="testFunction('{func_name}', 'POST')">POST</button>
                        <button class="method-btn put" onclick="testFunction('{func_name}', 'PUT')">PUT</button>
                        <button class="method-btn delete" onclick="testFunction('{func_name}', 'DELETE')">DELETE</button>
                    </div>
                </div>
            '''
    else:
        html += '''
                <div class="no-functions">
                    <p>📝 当前没有找到可用的Lambda函数</p>
                    <p>请确保您的Python文件中包含 <code>lambda_handler</code> 函数</p>
                </div>
        '''
    
    html += '''
            </div>
            
            <div class="test-section">
                <h3>🧪 交互式测试</h3>
                <form id="testForm">
                    <div class="form-row">
                        <div class="form-group">
                            <label for="functionName">函数名称:</label>
                            <input type="text" id="functionName" placeholder="输入函数名称" required>
                        </div>
                        <div class="form-group">
                            <label for="httpMethod">HTTP方法:</label>
                            <select id="httpMethod">
                                <option value="GET">GET</option>
                                <option value="POST">POST</option>
                                <option value="PUT">PUT</option>
                                <option value="DELETE">DELETE</option>
                            </select>
                        </div>
                    </div>
                    
                    <div class="form-group">
                        <label for="requestBody">请求体 (JSON):</label>
                        <textarea id="requestBody" rows="4" placeholder='{"key": "value"}'></textarea>
                    </div>
                    
                    <div class="form-group">
                        <label for="queryParams">查询参数:</label>
                        <input type="text" id="queryParams" placeholder="param1=value1&param2=value2">
                    </div>
                    
                    <button type="submit" class="submit-btn">🚀 发送请求</button>
                </form>
                
                <div class="loading" id="loading">
                    <div class="spinner"></div>
                    <p>正在处理请求...</p>
                </div>
                
                <div class="response-section" id="responseSection" style="display: none;">
                    <h4>📤 响应结果</h4>
                    <div class="response-content" id="responseContent"></div>
                </div>
            </div>
        </div>
    </div>

    <script>
        function testFunction(funcName, method) {
            document.getElementById('functionName').value = funcName;
            document.getElementById('httpMethod').value = method;
            document.getElementById('testForm').dispatchEvent(new Event('submit'));
        }
        
        document.getElementById('testForm').addEventListener('submit', async function(e) {
            e.preventDefault();
            
            const functionName = document.getElementById('functionName').value;
            const method = document.getElementById('httpMethod').value;
            const requestBody = document.getElementById('requestBody').value;
            const queryParams = document.getElementById('queryParams').value;
            
            const loading = document.getElementById('loading');
            const responseSection = document.getElementById('responseSection');
            const responseContent = document.getElementById('responseContent');
            
            loading.style.display = 'block';
            responseSection.style.display = 'none';
            
            try {
                let url = `/${functionName}`;
                if (queryParams) {
                    url += `?${queryParams}`;
                }
                
                const options = {
                    method: method,
                    headers: {
                        'Content-Type': 'application/json'
                    }
                };
                
                if (requestBody && method !== 'GET') {
                    options.body = requestBody;
                }
                
                const response = await fetch(url, options);
                const data = await response.text();
                
                let statusClass = response.ok ? 'status-success' : 'status-error';
                let statusText = response.ok ? '✅ 成功' : '❌ 错误';
                
                responseContent.innerHTML = `状态: <span class="${statusClass}">${statusText} (${response.status})</span>\n\n响应内容:\n${data}`;
                responseSection.style.display = 'block';
                
            } catch (error) {
                responseContent.innerHTML = `❌ 请求失败:\n${error.message}`;
                responseSection.style.display = 'block';
            } finally {
                loading.style.display = 'none';
            }
        });
    </script>
</body>
</html>
    '''
    
    return html

@app.errorhandler(HTTPException)
def handle_exception(e):
    """处理HTTP异常"""
    response = jsonify({
        'error': e.description,
        'code': e.code
    })
    response.headers['Content-Type'] = 'application/json; charset=utf-8'
    response = add_cors_headers(response)
    return response, e.code

if __name__ == '__main__':
    print("Lambda本地测试服务器启动中...")
    print(f"已加载的Lambda函数: {list(lambda_handlers.keys())}")
    print("访问 http://localhost:5476 查看可用函数")
    print("访问 http://localhost:5476/<function_name> 调用Lambda函数")
    
    app.run(host='0.0.0.0', port=5476, debug=True) 